/*
 * Copyright 2020-2025 the original author or authors.
 * You cannot use this file unless authorized by the author.
 */

package org.ipig.commons.helper;


import org.apache.commons.lang3.StringUtils;
import org.ipig.constants.DataCnst;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * String Helper
 *
 * @author <a href="mailto:comchnts@163.com">chinats</a>
 * @version $$Id: StringHelper.java 3 2020-01-21 09:36:33Z ts <comchnts@163.com> $$
 * @since 1.0
 */
public class StringHelper {
    //UTF_8
    private static final String UTF_8 = "UTF-8";
    public static final char UNDERLINE = '_';

    /**
     * 从字符串中获取英文字母[a-z,A-Z]
     *
     * @param msg 字符串
     * @return 英文字母
     */
    public static String getEnglishLetter(String msg) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < msg.length(); i++) {
            char c = msg.charAt(i);
            if ((c <= 'z' && c >= 'a') || (c <= 'Z' && c >= 'A')) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 返回{@code Object}参数的字符串表示形式
     *
     * @param obj an {@code Object}.
     * @return 如果参数为{@code null}, 则值为 {@code ""};否则,值为{@code obj.toString()}.
     */
    public static String valueOf(Object obj) {
        return (obj == null) ? StringUtils.EMPTY : obj.toString();
    }

    /**
     * decodeByUTF8
     *
     * @param json String
     * @return String
     */
    public static String decodeByUTF8(String json) {
        if (StringUtils.isBlank(json)) {
            return null;
        }
        try {
            json = URLDecoder.decode(json, UTF_8);
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
            return null;
        }
        return json;
    }

    /**
     * encodeByUTF8
     *
     * @param json String
     * @return String
     */
    public static String encodeByUTF8(String json) {
        if (StringUtils.isBlank(json)) {
            return null;
        }
        try {
            json = URLEncoder.encode(json, UTF_8);
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
            return null;
        }
        return json;

    }

    /**
     * 使用分隔符将字符串数组join起来
     *
     * @param separator 分隔符
     * @param strings   需要join的字符数组
     * @return
     */
    public static String join(CharSequence separator, String... strings) {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String s : strings) {
            if (first) {
                first = false;
            } else {
                sb.append(separator);
            }
            sb.append(s);
        }
        return sb.toString();
    }

    /**
     * match
     *
     * @param origValue        原始字符序列
     * @param matchPatternCode 匹配模式 来自DataCnst.MatchPattern
     * @param matchKey         匹配字符序列
     * @return boolean
     */
    public static boolean match(String origValue, String matchPatternCode, String matchKey) {
        DataCnst.MatchPattern matchPattern = DataCnst.MatchPattern.parse(matchPatternCode);
        return match(origValue, matchPattern, matchKey);
    }


    /**
     * match
     *
     * @param origValue    原始字符序列
     * @param matchPattern 匹配模式 DataCnst.MatchPattern
     * @param matchKey     匹配字符序列
     * @return boolean
     */
    public static boolean match(String origValue, final DataCnst.MatchPattern matchPattern, String matchKey) {
        boolean flag = false;
        if (matchPattern == DataCnst.MatchPattern.FULL) {
            if (StringUtils.equals(origValue, matchKey)) {
                flag = true;
            }
        } else if (matchPattern == DataCnst.MatchPattern.FUZZY) {
            if (StringUtils.indexOf(origValue, matchKey) >= 0) {
                flag = true;
            }
        } else if (matchPattern == DataCnst.MatchPattern.RIGHT) {
            int index = StringUtils.length(origValue) - StringUtils.length(matchKey);
            if (StringUtils.lastIndexOf(origValue, matchKey) == index) {
                flag = true;
            }
        } else {
            if (StringUtils.startsWith(origValue, matchKey)) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 循环匹配filed，并返回Map&lt;filed,filed在allFieldArgs中的位置索引&gt;
     * <ol>
     * <li>第一步用[allFieldsSeparator]分隔符，分隔[allFields]字符串，形成数组 [allFieldArgs]
     * <li>第二步用[fetchFieldsSeparator]分隔符，分隔[fetchFields]字符串，形成数组[fetchFieldArgs]
     * <li>第三步用[fetchFieldArgs]中的每个filed去[allFieldArgs]中匹配，
     * <ul>
     *     <li>匹配成功，组装Map&lt;filed,filed在allFieldArgs中的位置索引&gt;
     *     <li>匹配失败，组装Map&lt;filed,null&gt;
     * </ul>
     * </ol>
     * <ul>注意：
     * <li>当[fetchFieldArgs]中的field在[allFieldArgs]中不存在时，索引位置返回null
     * </ul>
     *
     * @param allFields            所有的字段
     * @param allFieldsSeparator   分隔符
     * @param fetchFields          需要获取的字段
     * @param fetchFieldsSeparator 分隔符
     * @param ignoreCase           boolean 匹配是否忽视大小写
     * @return Map<String, Integer>
     */
    public static Map<String, Integer> matchFields(final String allFields, final String allFieldsSeparator,
                                                   final String fetchFields, final String fetchFieldsSeparator,
                                                   final boolean ignoreCase) {
        String[] allFieldArgs = StringUtils.splitPreserveAllTokens(allFields, allFieldsSeparator);
        String[] fetchFieldArgs = StringUtils.splitPreserveAllTokens(fetchFields, fetchFieldsSeparator);
        return matchFields(allFieldArgs, fetchFieldArgs, ignoreCase);
    }


    /**
     * 循环匹配filed，并返回Map&lt;filed,filed在allFieldArgs中的位置索引&gt;
     * <li>用[fetchFieldArgs]中的每个filed去[allFieldArgs]中匹配，
     * <ul>
     *     <li>匹配成功，组装Map&lt;filed,filed在allFieldArgs中的位置索引&gt;
     *     <li>匹配失败，组装Map&lt;filed,null&gt;
     * </ul>
     * <ul>注意：
     * <li>当[fetchFieldArgs]中的field在[allFieldArgs]中不存在时，索引位置返回null
     * </ul>
     *
     * @param allFieldList   所有的字段
     * @param fetchFieldList 需要获取的字段
     * @param ignoreCase     boolean 匹配是否忽视大小写
     * @return Map<String, Integer>
     */
    public static Map<String, Integer> matchFields(final List<String> allFieldList,
                                                   final List<String> fetchFieldList,
                                                   final boolean ignoreCase) {
        Map<String, Integer> matchMap = null;
        if ((allFieldList == null || allFieldList.isEmpty()) &&
                (fetchFieldList != null && !fetchFieldList.isEmpty())) {
            int size = fetchFieldList.size();
            matchMap = new HashMap<>(size);
            for (int i = 0; i < size; i++) {
                matchMap.put(fetchFieldList.get(i), null);
            }
        } else if (fetchFieldList == null || fetchFieldList.isEmpty()) {
            matchMap = new HashMap<>(0);
        } else {
            String[] allFieldArgs = allFieldList.stream().toArray(String[]::new);
            String[] fetchFieldArgs = fetchFieldList.stream().toArray(String[]::new);
            matchMap = matchFields(allFieldArgs, fetchFieldArgs, ignoreCase);
        }
        return matchMap;
    }

    /**
     * 循环匹配filed，并返回Map&lt;filed,filed在allFieldArgs中的位置索引&gt;
     * <li>用[fetchFieldArgs]中的每个filed去[allFieldArgs]中匹配，
     * <ul>
     *     <li>匹配成功，组装Map&lt;filed,filed在allFieldArgs中的位置索引&gt;
     *     <li>匹配失败，组装Map&lt;filed,null&gt;
     * </ul>
     * <ul>注意：
     * <li>当[fetchFieldArgs]中的field在[allFieldArgs]中不存在时，索引位置返回null
     * </ul>
     *
     * @param allFieldArgs   所有的字段
     * @param fetchFieldArgs 需要获取的字段
     * @param ignoreCase     boolean 匹配是否忽视大小写
     * @return Map<String, Integer>
     */
    public static Map<String, Integer> matchFields(final String[] allFieldArgs,
                                                   final String[] fetchFieldArgs,
                                                   final boolean ignoreCase) {
        Map<String, Integer> matchMap = null;
        if ((allFieldArgs == null || allFieldArgs.length == 0)
                && (fetchFieldArgs != null && fetchFieldArgs.length > 0)) {
            int size = fetchFieldArgs.length;
            matchMap = new HashMap<>(size);
            for (int i = 0; i < size; i++) {
                matchMap.put(fetchFieldArgs[i], null);
            }
        } else if (fetchFieldArgs == null || fetchFieldArgs.length == 0) {
            matchMap = new HashMap<>(0);
        } else {
            int fetchLength = fetchFieldArgs.length;
            int allLength = allFieldArgs.length;
            matchMap = new HashMap<>(fetchLength);
            for (int i = 0; i < fetchLength; i++) {
                String fetchField = fetchFieldArgs[i];
                for (int j = 0; j < allLength; j++) {
                    if (ignoreCase) {
                        if (StringUtils.equalsIgnoreCase(fetchField, allFieldArgs[j])) {
                            matchMap.put(allFieldArgs[j], j);
                        }
                    } else {
                        if (StringUtils.equals(fetchField, allFieldArgs[j])) {
                            matchMap.put(allFieldArgs[j], j);
                        }
                    }
                }
                if (!matchMap.containsKey(fetchField)) {
                    matchMap.put(fetchField, null);
                }
            }
        }
        return matchMap;
    }


    /**
     * 下划线转驼峰
     * 将"_"转成驼峰(user_id:userId)
     *
     * @param underlineStr
     * @return
     */
    public static String underlineToCamel(String underlineStr) {
        if (StringUtils.isEmpty(underlineStr)) {
            return StringUtils.EMPTY;
        }
        int len = underlineStr.length();
        String msg = underlineStr.toLowerCase();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = msg.charAt(i);
            if (c == UNDERLINE && (++i) < len) {
                c = msg.charAt(i);
                sb.append(Character.toUpperCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}
